package datastructures;

import java.util.BitSet;

public class CarrierIndex {	
	//Each bitset is a vector of individuals. e.g. 2000 cases => a bitset of 2000 bits, 
	//with each bit set to 1 if the individual is a carrier, 0 if not.
	private BitSet[] caseStatus;
	private BitSet[] controlStatus;
	
	public CarrierIndex(int numberOfVariables) { 
		caseStatus = new BitSet[numberOfVariables];
		controlStatus = new BitSet[numberOfVariables];
	}  
	
	public void setCaseCarrierIndex(BitSet caseCarriers, int variable) {
		caseStatus[variable] = caseCarriers;
	}
	
	public void setControlCarrierIndex(BitSet controlCarriers, int variable) {
		controlStatus[variable] = controlCarriers;
	}
	
	
	public BitSet getCaseCarrierIndex(int variable) {
		return (BitSet) caseStatus[variable].clone();
	}
	
	public BitSet getControlCarrierIndex(int variable) {
		return (BitSet) controlStatus[variable].clone();
	}
	
	

	
	
	public int[][][] getObservedCaseCarriers(UserParameters userParams, int[] variableArray) {

		BitSet var1, var1not, var2, var2not, var3, var3not;
		BitSet temp111, temp110, temp101, temp100, temp011, temp010, temp001, temp000;
		int[][][] noOfCaseCarriers = new int[2][2][2];

		switch( variableArray.length ) {
		case 1:
			var1 = getCaseCarrierIndex( variableArray[0] );
			var1not = (BitSet) var1.clone();
			var1not.flip(0, userParams.getNumber_of_cases());

			temp111 = new BitSet(userParams.getNumber_of_cases());
			temp111.set(0, userParams.getNumber_of_cases());
			temp110 = (BitSet) temp111.clone();

			temp111.and(var1);
			temp110.and(var1not);

			noOfCaseCarriers[1][1][1] = temp111.cardinality();
			noOfCaseCarriers[1][1][0] = temp110.cardinality();
			break;

		case 2:
			var1 = getCaseCarrierIndex( variableArray[0] );
			var1not = (BitSet) var1.clone();
			var1not.flip(0, userParams.getNumber_of_cases());

			var2 = getCaseCarrierIndex( variableArray[1] );
			var2not = (BitSet) var2.clone();
			var2not.flip(0, userParams.getNumber_of_cases());

			temp111 = new BitSet(userParams.getNumber_of_cases());
			temp111.set(0, userParams.getNumber_of_cases());
			temp110 = (BitSet) temp111.clone();
			temp101 = (BitSet) temp111.clone();
			temp100 = (BitSet) temp111.clone();

			temp111.and(var1); temp111.and(var2);
			temp110.and(var1); temp110.and(var2not);
			temp101.and(var1not); temp101.and(var2);
			temp100.and(var1not); temp100.and(var2not);

			noOfCaseCarriers[1][1][1] = temp111.cardinality();
			noOfCaseCarriers[1][1][0] = temp110.cardinality();
			noOfCaseCarriers[1][0][1] = temp101.cardinality();
			noOfCaseCarriers[1][0][0] = temp100.cardinality();
			break;

		default: //case 3
		var1 = getCaseCarrierIndex( variableArray[0] );
		var1not = (BitSet) var1.clone();
		var1not.flip(0, userParams.getNumber_of_cases());

		var2 = getCaseCarrierIndex( variableArray[1] );
		var2not = (BitSet) var2.clone();
		var2not.flip(0, userParams.getNumber_of_cases());

		var3 = getCaseCarrierIndex( variableArray[2] );
		var3not = (BitSet) var2.clone();
		var3not.flip(0, userParams.getNumber_of_cases());

		temp111 = new BitSet(userParams.getNumber_of_cases());
		temp111.set(0, userParams.getNumber_of_cases());
		temp110 = (BitSet) temp111.clone();
		temp101 = (BitSet) temp111.clone();
		temp100 = (BitSet) temp111.clone();
		temp011 = (BitSet) temp111.clone();
		temp010 = (BitSet) temp111.clone();
		temp001 = (BitSet) temp111.clone();
		temp000 = (BitSet) temp111.clone();

		temp111.and(var1); temp111.and(var2); temp111.and(var3);
		temp110.and(var1); temp110.and(var2); temp110.and(var3not);
		temp101.and(var1); temp101.and(var2not); temp101.and(var3);
		temp100.and(var1); temp100.and(var2not); temp100.and(var3not);
		temp011.and(var1not); temp011.and(var2); temp011.and(var3);
		temp010.and(var1not); temp010.and(var2); temp010.and(var3not);
		temp001.and(var1not); temp001.and(var2not); temp001.and(var3);
		temp000.and(var1not); temp000.and(var2not); temp000.and(var3not);

		noOfCaseCarriers[1][1][1] = temp111.cardinality();
		noOfCaseCarriers[1][1][0] = temp110.cardinality();
		noOfCaseCarriers[1][0][1] = temp101.cardinality();
		noOfCaseCarriers[1][0][0] = temp100.cardinality();
		noOfCaseCarriers[0][1][1] = temp011.cardinality();
		noOfCaseCarriers[0][1][0] = temp010.cardinality();
		noOfCaseCarriers[0][0][1] = temp001.cardinality();
		noOfCaseCarriers[0][0][0] = temp000.cardinality();
		break;
		}

		return noOfCaseCarriers;
	}
	
	 
	public int[][][] getObservedControlCarriers(UserParameters userParams, int[] variableArray) {
			
		BitSet var1, var1not, var2, var2not, var3, var3not;
		BitSet temp111, temp110, temp101, temp100, temp011, temp010, temp001, temp000;
		int[][][] noOfControlCarriers = new int[2][2][2];
	
		switch( variableArray.length ) {
			case 1:
				var1 = getControlCarrierIndex( variableArray[0] );
				var1not = (BitSet) var1.clone();
				var1not.flip(0, userParams.getNumber_of_controls());
		
				temp111 = new BitSet(userParams.getNumber_of_controls());
				temp111.set(0, userParams.getNumber_of_controls());
				temp110 = (BitSet) temp111.clone();
		
				temp111.and(var1);
				temp110.and(var1not);
		
				noOfControlCarriers[1][1][1] = temp111.cardinality();
				noOfControlCarriers[1][1][0] = temp110.cardinality();
				break;
		
			case 2:
				var1 = getControlCarrierIndex( variableArray[0] ); 
				var1not = (BitSet) var1.clone();
				var1not.flip(0, userParams.getNumber_of_controls());
		
				var2 = getControlCarrierIndex( variableArray[1] );
				var2not = (BitSet) var2.clone();
				var2not.flip(0, userParams.getNumber_of_controls());
		
				temp111 = new BitSet(userParams.getNumber_of_controls());
				temp111.set(0, userParams.getNumber_of_controls());
				temp110 = (BitSet) temp111.clone();
				temp101 = (BitSet) temp111.clone();
				temp100 = (BitSet) temp111.clone();
		
				temp111.and(var1); temp111.and(var2);
				temp110.and(var1); temp110.and(var2not);
				temp101.and(var1not); temp101.and(var2);
				temp100.and(var1not); temp100.and(var2not);
		
				noOfControlCarriers[1][1][1] = temp111.cardinality();
				noOfControlCarriers[1][1][0] = temp110.cardinality();
				noOfControlCarriers[1][0][1] = temp101.cardinality();
				noOfControlCarriers[1][0][0] = temp100.cardinality();
				break;
		
				default: //case 3
				var1 = getControlCarrierIndex( variableArray[0] );
				var1not = (BitSet) var1.clone();
				var1not.flip(0, userParams.getNumber_of_controls());
			
				var2 = getControlCarrierIndex( variableArray[1] );
				var2not = (BitSet) var2.clone();
				var2not.flip(0, userParams.getNumber_of_controls());
			
				var3 = getControlCarrierIndex( variableArray[2] );
				var3not = (BitSet) var2.clone();
				var3not.flip(0, userParams.getNumber_of_controls());
			
				temp111 = new BitSet(userParams.getNumber_of_controls());
				temp111.set(0, userParams.getNumber_of_controls());
				temp110 = (BitSet) temp111.clone();
				temp101 = (BitSet) temp111.clone();
				temp100 = (BitSet) temp111.clone();
				temp011 = (BitSet) temp111.clone();
				temp010 = (BitSet) temp111.clone();
				temp001 = (BitSet) temp111.clone();
				temp000 = (BitSet) temp111.clone();
			
				temp111.and(var1); temp111.and(var2); temp111.and(var3);
				temp110.and(var1); temp110.and(var2); temp110.and(var3not);
				temp101.and(var1); temp101.and(var2not); temp101.and(var3);
				temp100.and(var1); temp100.and(var2not); temp100.and(var3not);
				temp011.and(var1not); temp011.and(var2); temp011.and(var3);
				temp010.and(var1not); temp010.and(var2); temp010.and(var3not);
				temp001.and(var1not); temp001.and(var2not); temp001.and(var3);
				temp000.and(var1not); temp000.and(var2not); temp000.and(var3not);
			
				noOfControlCarriers[1][1][1] = temp111.cardinality();
				noOfControlCarriers[1][1][0] = temp110.cardinality();
				noOfControlCarriers[1][0][1] = temp101.cardinality();
				noOfControlCarriers[1][0][0] = temp100.cardinality();
				noOfControlCarriers[0][1][1] = temp011.cardinality();
				noOfControlCarriers[0][1][0] = temp010.cardinality();
				noOfControlCarriers[0][0][1] = temp001.cardinality();
				noOfControlCarriers[0][0][0] = temp000.cardinality();
				break;
			}
		
		return noOfControlCarriers;
	}
			
}



//public double[][][] getExpectedCaseCarriers(UserParameters userParams, int[] variableArray) {
//BitSet var1, var1not, var2, var2not, var3, var3not;
//double[][][] expectedCaseCarriers = new double[2][2][2];
//
//switch( variableArray.length ) {
//
//	case 1:
//		var1 = getCaseCarrierIndex( variableArray[0] );	
//		var1not = (BitSet) var1.clone();
//		var1not.flip(0, userParams.getNumber_of_cases());
//		expectedCaseCarriers[1][1][1] = var1.cardinality();
//		expectedCaseCarriers[1][1][0] = var1not.cardinality();
//		break;
//
//	case 2:
//		var1 = getCaseCarrierIndex( variableArray[0] );
//		var1not = (BitSet) var1.clone();
//		var1not.flip(0, userParams.getNumber_of_cases());
//		
//		var2 = getCaseCarrierIndex( variableArray[1] );
//		var2not = (BitSet) var2.clone();
//		var2not.flip(0, userParams.getNumber_of_cases());
//		
//		expectedCaseCarriers[1][1][1] = (double) var1.cardinality() * (double) var2.cardinality() / userParams.getNumber_of_cases() ;
//		expectedCaseCarriers[1][1][0] = (double) var1.cardinality() * (double) var2not.cardinality() / userParams.getNumber_of_cases();
//		expectedCaseCarriers[1][0][1] = (double) var1not.cardinality() * (double) var2.cardinality() / userParams.getNumber_of_cases();
//		expectedCaseCarriers[1][0][0] = userParams.getNumber_of_cases() - expectedCaseCarriers[1][0][1] - expectedCaseCarriers[1][1][0] - expectedCaseCarriers[1][1][1];
//		break;
//
//	default: //case 3
//		var1 = getCaseCarrierIndex( variableArray[0] );
//		var1not = (BitSet) var1.clone();
//		var1not.flip(0, userParams.getNumber_of_cases());
//	
//		var2 = getCaseCarrierIndex( variableArray[1] );
//		var2not = (BitSet) var2.clone();
//		var2not.flip(0, userParams.getNumber_of_cases());
//	
//		var3 = getCaseCarrierIndex( variableArray[2] );
//		var3not = (BitSet) var2.clone();
//		var3not.flip(0, userParams.getNumber_of_cases());			
//	
//		expectedCaseCarriers[1][1][1] = (double) var1.cardinality() * (double) var2.cardinality() * (double) var3.cardinality() / Math.pow(userParams.getNumber_of_cases(),2) ;
//		expectedCaseCarriers[1][1][0] = (double) var1.cardinality() * (double) var2.cardinality() * (double) var3not.cardinality() / Math.pow(userParams.getNumber_of_cases(),2) ;
//		expectedCaseCarriers[1][0][1] = (double) var1.cardinality() * (double) var2not.cardinality() * (double) var3.cardinality() / Math.pow(userParams.getNumber_of_cases(),2) ;
//		expectedCaseCarriers[1][0][0] = (double) var1.cardinality() * (double) var2not.cardinality() * (double) var3not.cardinality() / Math.pow(userParams.getNumber_of_cases(),2) ;
//		expectedCaseCarriers[0][1][1] = (double) var1not.cardinality() * (double) var2.cardinality() * (double) var3.cardinality() / Math.pow(userParams.getNumber_of_cases(),2) ;
//		expectedCaseCarriers[0][1][0] = (double) var1not.cardinality() * (double) var2.cardinality() * (double) var3not.cardinality() / Math.pow(userParams.getNumber_of_cases(),2) ;
//		expectedCaseCarriers[0][0][1] = (double) var1not.cardinality() * (double) var2not.cardinality() * (double) var3.cardinality() / Math.pow(userParams.getNumber_of_cases(),2) ;
//		expectedCaseCarriers[0][0][0] = userParams.getNumber_of_cases() - expectedCaseCarriers[0][0][1] - expectedCaseCarriers[0][1][0] - expectedCaseCarriers[0][1][1] - expectedCaseCarriers[1][0][0] - expectedCaseCarriers[1][0][1] - expectedCaseCarriers[1][1][0] - expectedCaseCarriers[1][1][1];
//		break;
//}
//
//return expectedCaseCarriers;
//}



//public double[][][] getExpectedControlCarriers(UserParameters userParams, int[] variableArray) {
//BitSet var1, var1not, var2, var2not, var3, var3not;
//double[][][] expectedControlCarriers = new double[2][2][2];
//
//switch( variableArray.length ) {
//
//	case 1:
//		var1 = getControlCarrierIndex( variableArray[0] );	
//		var1not = (BitSet) var1.clone();
//		var1not.flip(0, userParams.getNumber_of_controls());
//		expectedControlCarriers[1][1][1] = var1.cardinality();
//		expectedControlCarriers[1][1][0] = var1not.cardinality();
//		break;
//
//	case 2:
//		var1 = getControlCarrierIndex( variableArray[0] );
//		var1not = (BitSet) var1.clone();
//		var1not.flip(0, userParams.getNumber_of_controls());
//		
//		var2 = getControlCarrierIndex( variableArray[1] );
//		var2not = (BitSet) var2.clone();
//		var2not.flip(0, userParams.getNumber_of_controls());
//		
//		expectedControlCarriers[1][1][1] = (double) var1.cardinality() * (double) var2.cardinality() / userParams.getNumber_of_controls() ;
//		expectedControlCarriers[1][1][0] = (double) var1.cardinality() * (double) var2not.cardinality() / userParams.getNumber_of_controls() ;
//		expectedControlCarriers[1][0][1] = (double) var1not.cardinality() * (double) var2.cardinality() / userParams.getNumber_of_controls() ;
//		expectedControlCarriers[1][0][0] =  userParams.getNumber_of_controls() - expectedControlCarriers[1][0][1] - expectedControlCarriers[1][1][0] - expectedControlCarriers[1][1][1];
//		break;
//
//	default: //case 3
//		var1 = getControlCarrierIndex( variableArray[0] );
//		var1not = (BitSet) var1.clone();
//		var1not.flip(0, userParams.getNumber_of_controls());
//	
//		var2 = getControlCarrierIndex( variableArray[1] );
//		var2not = (BitSet) var2.clone();
//		var2not.flip(0, userParams.getNumber_of_controls());
//	
//		var3 = getControlCarrierIndex( variableArray[2] );
//		var3not = (BitSet) var2.clone();
//		var3not.flip(0, userParams.getNumber_of_controls());			
//	
//		expectedControlCarriers[1][1][1] = (double) var1.cardinality() * (double) var2.cardinality() * (double) var3.cardinality() / Math.pow(userParams.getNumber_of_controls(),2) ;
//		expectedControlCarriers[1][1][0] = (double) var1.cardinality() * (double) var2.cardinality() * (double) var3not.cardinality() / Math.pow(userParams.getNumber_of_controls(),2) ;
//		expectedControlCarriers[1][0][1] = (double) var1.cardinality() * (double) var2not.cardinality() * (double) var3.cardinality() / Math.pow(userParams.getNumber_of_controls(),2) ;
//		expectedControlCarriers[1][0][0] = (double) var1.cardinality() * (double) var2not.cardinality() * (double) var3not.cardinality() / Math.pow(userParams.getNumber_of_controls(),2) ;
//		expectedControlCarriers[0][1][1] = (double) var1not.cardinality() * (double) var2.cardinality() * (double) var3.cardinality() / Math.pow(userParams.getNumber_of_controls(),2) ;
//		expectedControlCarriers[0][1][0] = (double) var1not.cardinality() * (double) var2.cardinality() * (double) var3not.cardinality() / Math.pow(userParams.getNumber_of_controls(),2) ;
//		expectedControlCarriers[0][0][1] = (double) var1not.cardinality() * (double) var2not.cardinality() * (double) var3.cardinality() / Math.pow(userParams.getNumber_of_controls(),2) ;
//		expectedControlCarriers[0][0][0] = userParams.getNumber_of_controls() - expectedControlCarriers[0][0][1] - expectedControlCarriers[0][1][0] - expectedControlCarriers[0][1][1] - expectedControlCarriers[1][0][0] - expectedControlCarriers[1][0][1] - expectedControlCarriers[1][1][0] - expectedControlCarriers[1][1][1];
//		break;
//}
//
//return expectedControlCarriers;
//}
